home *** CD-ROM | disk | FTP | other *** search
/ Windows Expert / Windows Expert.iso / windownt / uupc11yt.zip / RNEWS / RNEWS.C < prev    next >
C/C++ Source or Header  |  1993-04-17  |  48KB  |  1,369 lines

  1. /*--------------------------------------------------------------------*/
  2. /*    r n e w s . c                                                   */
  3. /*                                                                    */
  4. /*    Receive incoming news into the news directory.                  */
  5. /*                                                                    */
  6. /*    Written by Mike Lipsie; modified for UUPC/extended 1.11s by     */
  7. /*    Andrew H., Derbyshire.                                          */
  8. /*                                                                    */
  9. /*    Changes and Compilation Copyright (c) 1992 by Andrew H.         */
  10. /*    Derbyshire.  All rights reserved except as granted by the       */
  11. /*    general UUPC/extended license.                                  */
  12. /*                                                                    */
  13. /*    This package has been substantially modified.  It will now      */
  14. /*    copy compressed articles (assumed batches but they could be     */
  15. /*    single articles) to the CMPRSSED directory and it will          */
  16. /*    unbatch (if necessary) and deliver articles to their            */
  17. /*    appropriate newsgroup directories.  At the end, if the file     */
  18. /*    was compressed it will invoke a batch file which will           */
  19. /*    uncompress the file and then feed it back to rnews.             */
  20. /*                                                                    */
  21. /*    Appropriate is defined as                                       */
  22. /*                                                                    */
  23. /*       (a) the newsgroup is in the active file and                  */
  24. /*       (b) the directory name is the group name with all            */
  25. /*           the"."s replaced with "/"s and all of that under the     */
  26. /*           news directory.                                          */
  27. /*                                                                    */
  28. /*    Names are insured to be valid by ImportNewsGroup, which maps    */
  29. /*    invalid characters and truncates names as required.             */
  30. /*--------------------------------------------------------------------*/
  31.  
  32. /*--------------------------------------------------------------------*/
  33. /*                          RCS Information                           */
  34. /*--------------------------------------------------------------------*/
  35.  
  36. /*
  37.  *       $Id: RNEWS.C 1.9 1993/04/17 13:40:39 ahd Exp $
  38.  *
  39.  *       $Log: RNEWS.C $
  40.  * Revision 1.9  1993/04/17  13:40:39  ahd
  41.  * fix compile errors for snews fix
  42.  *
  43.  * Revision 1.8  1993/04/17  13:23:37  ahd
  44.  * make snews option more compatible with snews (which is brain dead)
  45.  *
  46.  * Revision 1.7  1993/04/16  12:55:36  dmwatt
  47.  * Bounds check group lengths
  48.  *
  49.  * Revision 1.5  1993/04/11  00:33:54  ahd
  50.  * Global edits for year, TEXT, etc.
  51.  *
  52.  * Revision 1.4  1993/03/24  01:57:30  ahd
  53.  * Corrections for short articles
  54.  * Corrections for articles claimed to be zero length
  55.  * Resync gracefully after incorrect length descriptor
  56.  *
  57.  * Revision 1.3  1993/03/06  23:04:54  ahd
  58.  * Do not delete open files
  59.  *
  60.  * Revision 1.2  1992/11/22  21:14:21  ahd
  61.  * Reformat selected sections of code
  62.  * Check for premature end of articles in batched news
  63.  *
  64.  */
  65.  
  66. static const char rcsid[] =
  67.          "$Id: RNEWS.C 1.9 1993/04/17 13:40:39 ahd Exp $";
  68.  
  69. /*--------------------------------------------------------------------*/
  70. /*                        System include files                        */
  71. /*--------------------------------------------------------------------*/
  72.  
  73. #include <stdio.h>
  74. #include <stdlib.h>
  75. #include <string.h>
  76. #include <ctype.h>
  77. #include <time.h>
  78. #include <fcntl.h>
  79. #include <io.h>
  80. #include <process.h>
  81.  
  82. /*--------------------------------------------------------------------*/
  83. /*                    UUPC/extended include files                     */
  84. /*--------------------------------------------------------------------*/
  85.  
  86. #include "lib.h"
  87. #include "active.h"
  88. #include "getopt.h"
  89. #include "getseq.h"
  90. #include "history.h"
  91. #include "hlib.h"
  92. #include "import.h"
  93. #include "importng.h"
  94. #include "logger.h"
  95. #include "timestmp.h"
  96.  
  97. /*--------------------------------------------------------------------*/
  98. /*                           Global defines                           */
  99. /*--------------------------------------------------------------------*/
  100.  
  101. #define UNCOMPRESS "uncompre"
  102.  
  103. /*--------------------------------------------------------------------*/
  104. /*                          Global variables                          */
  105. /*--------------------------------------------------------------------*/
  106.  
  107. currentfile();
  108.  
  109. extern struct grp *group_list;   /* List of all groups */
  110.  
  111. FILE *hfile = NULL;           /* History file */
  112. char history_date[12];        /* dd/mm/yyyy + null + 1 for no good reason */
  113. char hbuff[BUFSIZ];
  114.  
  115. /*--------------------------------------------------------------------*/
  116. /*                       Functions in this file                       */
  117. /*--------------------------------------------------------------------*/
  118.  
  119. static boolean deliver_article(char *art_fname);
  120.                               /* Distribute the article to the
  121.                                  proper newsgroups                   */
  122.  
  123. static void copy_file(FILE *f,
  124.             char *group,
  125.             char *xref);      /* Copy file (f) to newsgroup          */
  126.  
  127. static struct grp *find_newsgroup(const char *grp);
  128.                               /* Get the grp struct for the newsgroup */
  129.  
  130. static void get_snum(const char *group, char *snum);
  131.                                     /* Get (and format) the next article
  132.                                        number in group                     */
  133.  
  134. static void fixEOF( char *buf, int bytes );
  135.  
  136. static int Single( char *filename , FILE *stream );
  137.  
  138. static int Compressed( char *filename , FILE *in_stream );
  139.  
  140. static int Batched( char *filename, FILE *stream);
  141.  
  142. static void xmit_news( char *sysname, FILE *in_stream );
  143.  
  144. static int copy_snews( char *filename, FILE *stream );
  145.  
  146. /*--------------------------------------------------------------------*/
  147. /*    m a i n                                                         */
  148. /*                                                                    */
  149. /*    Main program                                                    */
  150. /*                                                                    */
  151. /*    Exit conditions                                                 */
  152. /*                                                                    */
  153. /*    0 - Success                                                     */
  154. /*    1 - System configuration failed                                 */
  155. /*    2 - Unable to open working file                                 */
  156. /*    4 - out of memory                                               */
  157. /*    5 - Unable to create history dbm file                           */
  158. /*    6 - Problem decompressing news batch                            */
  159. /*    7 - Unable to create cmprssed directory                         */
  160. /*--------------------------------------------------------------------*/
  161.  
  162. void main( int argc, char **argv)
  163. {
  164.  
  165.    struct tm *local_now;
  166.  
  167.    long now = time(nil(long));
  168.    FILE *f;
  169.    char in_filename[FILENAME_MAX];
  170.    char filename[FILENAME_MAX];
  171.    int c;
  172.    int status;
  173.  
  174. #if defined(__CORE__)
  175.    copywrong = strdup(copyright);
  176.    checkref(copywrong);
  177. #endif
  178.  
  179.    banner( argv );
  180.  
  181.    if (!configure( B_NEWS ))
  182.       exit(1);    /* system configuration failed */
  183.  
  184.    openlog( NULL );           /* Begin logging to disk            */
  185.  
  186.    if (argc > 1)
  187.    {
  188.       int option;
  189.  
  190.     /*------------------------------------------------------------*/
  191.     /*                          parse arguments                   */
  192.     /*------------------------------------------------------------*/
  193.  
  194.        while ((option = getopt(argc, argv, "f:x:")) != EOF)
  195.        {
  196.            switch (option)
  197.            {
  198.                case 'f':
  199.                   strcpy(in_filename, optarg);
  200.                   f = freopen(in_filename, "r", stdin);
  201.                   if (f == NULL) {
  202.                      printerr( in_filename );
  203.                      panic();
  204.                   } else
  205.                      printmsg(2, "Opened %s as newsfile", in_filename);
  206.  
  207.                   break;
  208.  
  209.                case 'x':
  210.                   debuglevel = atoi(optarg);
  211.                   break;
  212.  
  213.                case '?':
  214.                   puts("\nUsage:\trnews [-f newsfile] [-x debug]");
  215.                   return;
  216.            } /* break */
  217.  
  218.        } /* while */
  219.     } /* if (argc > 1) */
  220.  
  221.    tzset();                   /* Set up time zone information  */
  222.  
  223. /*--------------------------------------------------------------------*/
  224. /*    If we are processing snews input, write it all out to the       */
  225. /*    news directory as one file and return gracefully.               */
  226. /*--------------------------------------------------------------------*/
  227.  
  228.    if ( bflag[F_SNEWS])
  229.    {
  230.       char *savetemp = E_tempdir;   /* Save the real temp directory  */
  231.  
  232.       if (bflag[F_HISTORY])
  233.       {
  234.          printmsg(0,
  235.                "rnews: Conflicting options snews and history specified!");
  236.          panic();
  237.       } /* else if */
  238.  
  239.  
  240.       E_tempdir = E_newsdir;        /* Generate this file in news    */
  241.       mktempname(filename, "ART");  /* Get the file name             */
  242.       E_tempdir = savetemp;         /* Restore true directory name   */
  243.       exit (copy_snews( filename, stdin ));
  244.                                     /* Dump news into NEWS directory */
  245.    }
  246.    else
  247.       mktempname(filename, "tmp");  /* Make normal temp name         */
  248.  
  249. /*--------------------------------------------------------------------*/
  250. /*             Load the active file and validate its data             */
  251. /*--------------------------------------------------------------------*/
  252.  
  253.    get_active();           /* Get sequence numbers for groups
  254.                               from active file                 */
  255.    validate_newsgroups();  /* Make sure all directories exist  */
  256.  
  257. /*--------------------------------------------------------------------*/
  258. /*                   Initialize history processing                    */
  259. /*--------------------------------------------------------------------*/
  260.  
  261.    local_now = localtime(&now);
  262.  
  263.    sprintf(history_date, "%2.2d/%2.2d/%4d",  local_now->tm_mday,
  264.                                  local_now->tm_mon+1,
  265.                                  local_now->tm_year+1900);
  266.  
  267. /*--------------------------------------------------------------------*/
  268. /*                 Open (or create) the history file                  */
  269. /*--------------------------------------------------------------------*/
  270.  
  271.    if ( bflag[F_HISTORY] )
  272.    {
  273.       if (history_exists())
  274.          hfile = open_history(history_date);
  275.       else
  276.          hfile = create_history(history_date);
  277.    } /* if */
  278.  
  279. /*--------------------------------------------------------------------*/
  280. /*    This loop copies the file to the NEWS directory.                */
  281. /*                                                                    */
  282. /*    A news article/batch either has a '#' character as its first    */
  283. /*    character or it does not.                                       */
  284. /*                                                                    */
  285. /*    If it does not it is a single (unbatched, uncompressed)         */
  286. /*    article.                                                        */
  287. /*                                                                    */
  288. /*    If the first character _is_ a '#', the first line is #!         */
  289. /*    cunbatch\n which means that it is a compressed batch; it        */
  290. /*    will be uncompressed and then re-fed to rnews or the first      */
  291. /*    line can be #! rnews nnn\n (where nnn is some number) which     */
  292. /*    means that the next nnn characters are an article and that      */
  293. /*    more might follow.                                              */
  294. /*                                                                    */
  295. /*    Due to a "feature" in the compressed batch, there may be        */
  296. /*    _no_ articles batched (an article destined for transmittal      */
  297. /*    is cancelled before being sent).                                */
  298. /*                                                                    */
  299. /*    Since this is a bit spread out, the various clauses of the      */
  300. /*    if statement will be marked with boxed 1, 2, or 3 (and a        */
  301. /*    brief explanation.                                              */
  302. /*--------------------------------------------------------------------*/
  303.  
  304. /*--------------------------------------------------------------------*/
  305. /*    Compressed files need to be read in BINARY mode so that         */
  306. /*    "magic" characters (like ^Z) don't upset it.  Batched files     */
  307. /*    need to be read in TEXT mode so that the character count is     */
  308. /*    correct.  The other case doesn't matter.                        */
  309. /*--------------------------------------------------------------------*/
  310.  
  311.    c = getc(stdin);
  312.    ungetc(c, stdin);
  313.  
  314.    if (c != '#') {
  315.  
  316.       /***********************************************/
  317.       /* 1  single (unbatched, uncompressed) article */
  318.       /***********************************************/
  319.  
  320.       status = Single(filename, stdin);
  321.  
  322.    }
  323.    else {
  324.  
  325.       char buf[BUFSIZ];
  326.       int fields = fscanf(stdin, "#! %s ", &buf);
  327.       if ((fields == 1) && (strcmp(buf, "cunbatch") == 0))
  328.       {
  329.  
  330.          /***********************************************/
  331.          /*  2  Compressed batch                        */
  332.          /***********************************************/
  333.  
  334.          status = Compressed(filename, stdin);
  335.  
  336.       }
  337.       else {
  338.  
  339.          /***********************************************/
  340.          /* 3  Uncompressed batch                       */
  341.          /***********************************************/
  342.  
  343.          status = Batched( filename, stdin );
  344.       } /* else */
  345.    } /* else */
  346.  
  347. /*--------------------------------------------------------------------*/
  348. /*                     Close open files and exit                      */
  349. /*--------------------------------------------------------------------*/
  350.  
  351.    put_active();
  352.  
  353.    if (hfile != NULL)
  354.       fclose(hfile);
  355.  
  356.    exit(status);
  357.  
  358. } /*main*/
  359.  
  360. /*--------------------------------------------------------------------*/
  361. /*    S i n g l e                                                     */
  362. /*                                                                    */
  363. /*    Deliver a single article to the proper news group(s)            */
  364. /*--------------------------------------------------------------------*/
  365.  
  366. static int Single( char *filename , FILE *stream )
  367. {
  368.    char tmp_fname[FILENAME_MAX];
  369.    FILE *tmpf;
  370.    char buf[BUFSIZ];
  371.    unsigned chars_read;
  372.    unsigned chars_written;
  373.  
  374.  
  375. /*--------------------------------------------------------------------*/
  376. /* Make a file name and then open the file to write the article into  */
  377. /*--------------------------------------------------------------------*/
  378.  
  379.    tmpf = FOPEN(filename, "w", BINARY_MODE);
  380.  
  381.    if ( tmpf == NULL )
  382.    {
  383.       printerr( tmp_fname );
  384.       panic();
  385.    }
  386.  
  387. /*--------------------------------------------------------------------*/
  388. /*              Now copy the input into our holding bin               */
  389. /*--------------------------------------------------------------------*/
  390.  
  391.    while ((chars_read = fread(buf,sizeof(char), BUFSIZ, stream)) != 0)
  392.    {
  393.  
  394.       chars_written = fwrite(buf, sizeof(char), chars_read, tmpf);
  395.       if (chars_written != chars_read)
  396.       {
  397.          printerr( filename );
  398.          printmsg(0, "rnews: Error writing single article to working file");
  399.          fclose( tmpf );
  400.          unlink( filename );
  401.          panic();
  402.       }
  403.    }
  404.  
  405. /*--------------------------------------------------------------------*/
  406. /*     Close the file, deliver the article, and return the caller     */
  407. /*--------------------------------------------------------------------*/
  408.  
  409.    fclose(tmpf);
  410.  
  411.    deliver_article(filename);
  412.    unlink( filename );
  413.    return 0;
  414.  
  415. } /* Single */
  416.  
  417. /*--------------------------------------------------------------------*/
  418. /*    C o m p r e s s e d                                             */
  419. /*                                                                    */
  420. /*    Decompress news                                                 */
  421. /*--------------------------------------------------------------------*/
  422.  
  423. static int Compressed( char *filename , FILE *in_stream )
  424. {
  425.  
  426.    FILE *work_stream;
  427.  
  428.    char zfile[FILENAME_MAX];
  429.    char unzfile[FILENAME_MAX];
  430.    char buf[BUFSIZ];
  431.  
  432.    boolean first_time = TRUE;
  433.    char *program, *args;
  434.    long cfile_size = 0L;
  435.    size_t chars_read, i;
  436.    int status = 0;
  437.    boolean needtemp = TRUE;
  438.  
  439.    char *sysname;             /* For reading systems to process   */
  440.  
  441. /*--------------------------------------------------------------------*/
  442. /*        Copy the compressed file to the "holding" directory         */
  443. /*--------------------------------------------------------------------*/
  444.  
  445.    setmode(fileno(in_stream), O_BINARY);/* Don't die on control-Z, etc */
  446.    fseek(in_stream, 0L, SEEK_SET);      /* Back to the beginning       */
  447.  
  448.  
  449.    while( needtemp )
  450.    {
  451.       mktempname( zfile , "Z" );          /* Generate "compressed" file
  452.                                           name                       */
  453.       strcpy( unzfile, zfile );
  454.       unzfile[ strlen(unzfile)-2 ] = '\0';
  455.  
  456.       if ( access( unzfile, 0 ))  /* Does the host file exist?       */
  457.          needtemp = FALSE;        /* No, we have a good pair         */
  458.       else
  459.          printmsg(0,"Had compressed name %s, found %s already exists!",
  460.                   zfile, unzfile );
  461.  
  462.    } /* while */
  463.  
  464. /*--------------------------------------------------------------------*/
  465. /*                 Open the file, with error recovery                 */
  466. /*--------------------------------------------------------------------*/
  467.  
  468.    if ((work_stream = FOPEN(zfile, "w", BINARY_MODE)) == nil(FILE))
  469.    {
  470.       printmsg(0, "Compressed: Can't open %s (%d)", zfile, errno);
  471.       printerr(zfile);
  472.       return 2;
  473.    }
  474.  
  475.    printmsg(2, "Compressed: Copy to %s for later processing", zfile);
  476.  
  477. /*--------------------------------------------------------------------*/
  478. /*                 Main loop to copy compressed file                  */
  479. /*--------------------------------------------------------------------*/
  480.  
  481.    while ((chars_read = fread(buf,sizeof(char), BUFSIZ, in_stream)) != 0)
  482.    {
  483.       char *t_buf = buf;
  484.       if (first_time)
  485.       {
  486.          t_buf += sizeof("#! cunbatch");
  487.  
  488.          first_time = FALSE;
  489.          chars_read -= (t_buf - buf);
  490.  
  491.          while ((*t_buf == ' ') || (*t_buf == '\n') || (*t_buf == '\r'))
  492.          {
  493.             t_buf++;
  494.             chars_read--;
  495.          } /* while */
  496.  
  497.       } /* if */
  498.  
  499.       i = fwrite(t_buf,sizeof(char),chars_read,work_stream);
  500.  
  501.       if (i != chars_read)
  502.       {
  503.          fclose( work_stream );
  504.          printerr( zfile );
  505.          panic();
  506.       }
  507.  
  508.       cfile_size += (long)chars_read;
  509.    } /* while */
  510.  
  511.    fclose(work_stream);
  512.  
  513. /*--------------------------------------------------------------------*/
  514. /*             If the file is empty, delete it gracefully             */
  515. /*--------------------------------------------------------------------*/
  516.  
  517.    if (cfile_size == 3)
  518.    {
  519.       unlink(zfile); /* Get rid of null file */
  520.       printmsg(1, "Compressed: %s empty, deleted", zfile);
  521.       return status;
  522.    }
  523.    else
  524.       printmsg(2,"Compressed: Copy to %s complete, %ld characters",
  525.                zfile, cfile_size);
  526.  
  527. /*--------------------------------------------------------------------*/
  528. /*      Special hack for creating mirror images of the news feed      */
  529. /*--------------------------------------------------------------------*/
  530.  
  531.    sysname = getenv( "UUPCSHADOWS" );
  532.  
  533.    if ( sysname != NULL )
  534.    {
  535.       strcpy( buf, sysname);
  536.  
  537.       sysname = strtok( buf, WHITESPACE );
  538.  
  539.       while( sysname != NULL )
  540.       {
  541.          printmsg(1,"Compressed: Shadowing news to %s", sysname );
  542.          fseek(in_stream, 0L, SEEK_SET);      /* Back to the beginning       */
  543.          xmit_news( sysname, in_stream );
  544.          sysname = strtok( NULL, WHITESPACE );
  545.       }
  546.  
  547.    } /* if */
  548.  
  549. /*--------------------------------------------------------------------*/
  550. /*          Uncompress the article and feed it back to rnews          */
  551. /*--------------------------------------------------------------------*/
  552.  
  553.    if ( E_uncompress == NULL )
  554.    {
  555.       program = UNCOMPRESS;
  556.       args    = zfile;
  557.       printmsg(2,"Compressed: %s %s", program , args);
  558.    }
  559.    else {
  560.       sprintf( buf, E_uncompress, zfile, unzfile );
  561.       printmsg(2,"Compressed: %s", buf );
  562.  
  563.       program = strtok( buf, WHITESPACE );
  564.       args = strtok( NULL, "");
  565.  
  566.       if ( args != NULL )
  567.          while (isspace(*args))
  568.             args++;
  569.  
  570.    }
  571.  
  572.    status = spawnlp(P_WAIT, program, program, args, NULL);
  573.  
  574.    unlink( zfile );           /* Kill the compressed input file      */
  575.  
  576.    if (status != 0)
  577.    {
  578.       if (status == -1)
  579.       {
  580.           printmsg( 0, "Compress: spawn failed completely" );
  581.           printerr( program );
  582.       }
  583.       else
  584.           printmsg(0, "%s command failed (exit code %d)",
  585.                         UNCOMPRESS, status);
  586.       panic();
  587.    } /* if status != 0 */
  588.  
  589. /*--------------------------------------------------------------------*/
  590. /*            Now process the file as normal batched news             */
  591. /*--------------------------------------------------------------------*/
  592.  
  593.                               /* Create uncompressed output file name   */
  594.  
  595.    work_stream = FOPEN( unzfile, "r", BINARY_MODE);
  596.    if ( work_stream == NULL )
  597.    {
  598.       printerr( unzfile );
  599.       panic();
  600.    }
  601.  
  602.    status = Batched( filename, work_stream );
  603.  
  604. /*--------------------------------------------------------------------*/
  605. /*                   Clean up and return to caller                    */
  606. /*--------------------------------------------------------------------*/
  607.  
  608.    fclose( work_stream );
  609.    unlink( unzfile );
  610.  
  611.    return status;
  612.  
  613. } /* Compressed */
  614.  
  615. /*--------------------------------------------------------------------*/
  616. /*    B a t c h e d                                                   */
  617. /*                                                                    */
  618. /*    Handle batched, uncompressed news                               */
  619. /*--------------------------------------------------------------------*/
  620.  
  621. static int Batched( char *filename, FILE *stream)
  622. {
  623.  
  624.    char buf[BUFSIZ * 2];
  625.    int status = 0;
  626.    long article_size;
  627.    int articles = 0;
  628.    int ignored  = 0;
  629.    boolean gotsize = FALSE;
  630.    int chars_read;
  631.    int chars_written;
  632.  
  633. /*--------------------------------------------------------------------*/
  634. /*    This is an uncompressed batch.  Copy it to the working          */
  635. /*    directory and then distribute the individual articles.          */
  636. /*--------------------------------------------------------------------*/
  637.  
  638.    setmode(fileno(stream), O_BINARY ); /* Don't die on Cntrl Z, etc.  */
  639.    fseek(stream, 0L, SEEK_SET);        /* Back to the beginning       */
  640.  
  641.    while( ! feof( stream ) && ! ferror( stream ))
  642.    {
  643.       long article_left;
  644.       int  max_read = (long) sizeof buf;
  645.       long skipped_lines = 0;
  646.       long skipped_bytes = 0;
  647.       FILE *tmpf;
  648.  
  649.  /*--------------------------------------------------------------------*/
  650.  /*    Handle next article (articles are separated by the line         */
  651.  /*    indicating their size when they are batched.)                   */
  652.  /*--------------------------------------------------------------------*/
  653.  
  654.       while ( ! gotsize )
  655.       {
  656.          if (fgets( buf, sizeof buf, stream ) == NULL)
  657.             break;
  658.  
  659.          if ( equaln( "#! rnews", buf, 8) )
  660.          {
  661.             article_size = 0;
  662.             sscanf(buf, "#! rnews %ld \n", &article_size);
  663.             gotsize = TRUE;
  664.          }
  665.          else {
  666.             skipped_lines ++;
  667.             skipped_bytes += strlen( buf );
  668.          }
  669.       } /* while */
  670.  
  671.       if ( skipped_lines )
  672.          printmsg(0,
  673.                   "Batched: Skipped %ld bytes in %ld "
  674.                   "lines after article %d",
  675.                   skipped_bytes,
  676.                   skipped_lines,
  677.                   articles );
  678.  
  679. /*--------------------------------------------------------------------*/
  680. /*                          Trap end of file                          */
  681. /*--------------------------------------------------------------------*/
  682.  
  683.       if ( ! gotsize )
  684.       {
  685.          if ( ferror( stream ))
  686.             printerr( "stdin" );
  687.          break;
  688.       }
  689.  
  690.       article_left = article_size;
  691.       gotsize = FALSE;
  692.  
  693. /*--------------------------------------------------------------------*/
  694. /*                   Open up our next working file                    */
  695. /*--------------------------------------------------------------------*/
  696.  
  697.       tmpf = FOPEN(filename, "w", BINARY_MODE);
  698.       if ( tmpf == NULL )
  699.       {
  700.          printerr( filename );
  701.          panic();
  702.       }
  703.  
  704.  /*--------------------------------------------------------------------*/
  705.  /*   Copy this article to the temp file (except for the last block)   */
  706.  /*--------------------------------------------------------------------*/
  707.  
  708.       if ( article_size )
  709.       {
  710.          do {
  711.             if ( article_left < max_read )
  712.                max_read = (int) article_left;
  713.  
  714.             chars_read = fread(buf, sizeof(char), max_read, stream);
  715.  
  716.             if ( (chars_read < max_read) && ferror( stream ))
  717.             {
  718.                printerr("STDIN");
  719.                panic();
  720.             }
  721.  
  722.             if ( chars_read == 0)
  723.                break;
  724.  
  725.             fixEOF( buf , chars_read );
  726.  
  727.             chars_written = fwrite(buf, sizeof(char), chars_read, tmpf);
  728.             if (chars_read != chars_written)
  729.             {
  730.                printmsg(0,"Batched: Read %d bytes, only wrote %d bytes of article %d",
  731.                      chars_read, chars_written , articles + 1);
  732.                printerr(filename);
  733.             }
  734.  
  735.             article_left -= chars_read;
  736.  
  737.          } while (article_left > 0);
  738.  
  739.          if ( article_left )     // Premature EOF?
  740.             printmsg(0,"Batched: Unexpected EOF for article %d, "
  741.                      "read %ld bytes of expected %ld",
  742.                       articles + 1,
  743.                       article_size - article_left, article_size );
  744.  
  745.       } /* if */
  746.       else {
  747.  
  748.          long actual_size = 0;
  749.  
  750.          do {
  751.             if (fgets( buf, sizeof buf, stream ) == NULL)
  752.             {
  753.                if ( ferror( stream ))
  754.                   printerr( filename );
  755.                break;
  756.             }
  757.  
  758.             chars_read = strlen( buf );
  759.  
  760.             if ( equaln( "#! rnews", buf, 8) )
  761.             {
  762.                sscanf(buf, "#! rnews %ld \n", &article_size);
  763.                gotsize = TRUE;
  764.             }
  765.             else if ( chars_read > 0 )
  766.             {
  767.                actual_size += chars_read;
  768.  
  769.                chars_written = fwrite(buf,
  770.                                       sizeof(char),
  771.                                       chars_read,
  772.                                       tmpf);
  773.                if (chars_read != chars_written)
  774.                {
  775.                   printmsg(0,
  776.                        "Batched: Read %d bytes, only wrote %d bytes of article %d",
  777.                         chars_read, chars_written , articles + 1);
  778.                   printerr(filename);
  779.                }
  780.             } /* else */
  781.  
  782.          } while( ! gotsize );
  783.  
  784.          printmsg(2,"Batched: Article %d size %ld",
  785.                      articles + 1,
  786.                      actual_size );
  787.       } /* else */
  788.  
  789.  /*--------------------------------------------------------------------*/
  790.  /*      Close the file, deliver its contents, and get rid of it       */
  791.  /*--------------------------------------------------------------------*/
  792.  
  793.       fclose(tmpf);
  794.       if ( ! deliver_article(filename) )
  795.          ignored ++;
  796.       unlink( filename );
  797.       articles ++;
  798.  
  799.    } /* while */
  800.  
  801. /*--------------------------------------------------------------------*/
  802. /*                          Return to caller                          */
  803. /*--------------------------------------------------------------------*/
  804.  
  805.    if ( ignored )
  806.       printmsg(1,"Batched: Unbatched %d articles (discarded %d of these)",
  807.                articles , ignored);
  808.    else
  809.       printmsg(1,"Batched: Unbatched %d articles", articles );
  810.    return status;
  811.  
  812. } /* Batched */
  813.  
  814. /*--------------------------------------------------------------------*/
  815. /*    f i x E O F                                                     */
  816. /*                                                                    */
  817. /*    Zap Cntrl-Z characters in the input stream                      */
  818. /*--------------------------------------------------------------------*/
  819.  
  820. static void fixEOF( char *buf, int bytes )
  821. {
  822.    static warn = TRUE;
  823.  
  824.    while ( bytes-- )
  825.    {
  826.       if ( *buf == ('Z' - 'A'))
  827.       {
  828.          *buf = 'Z';
  829.          if ( warn )
  830.          {
  831.             printmsg(0,"Altered Cntl-Z to Z");
  832.             warn = FALSE;
  833.          } /* if */
  834.       } /* if */
  835.    } /* while */
  836.  
  837. } /* fixEOF */
  838.  
  839. /*--------------------------------------------------------------------*/
  840. /*    d e l i v e r _ a r t i c l e                                   */
  841. /*                                                                    */
  842. /*    Determine delivery of a posting                                 */
  843. /*--------------------------------------------------------------------*/
  844.  
  845. static boolean deliver_article(char *art_fname)
  846. {
  847.  
  848.    char groupy[MAXGRP];
  849.  
  850.    char *newsgroups = NULL;   /* The Newsgroups: line */
  851.    char *messageID  = NULL;   /* The Message-ID: line */
  852.  
  853.    char *gc_ptr;           /* Scratch pointers.  Mostly used to go */
  854.    char *gc_ptr1;              /*   down the list of newsgroups.      */
  855.  
  856.    FILE *tfile;            /* The article file */
  857.  
  858.    int n_hdrs;             /* Number of desired headers seen */
  859.    int b_xref;
  860.  
  861.    int line_len;
  862.  
  863.    char hist_record[BUFSIZ];  /* buffer for history file
  864.                                  (also used for article)             */
  865.    char groups[BUFSIZ];
  866.    char message_buf[BUFSIZ];
  867.    char snum[10];
  868.  
  869.    tfile = FOPEN(art_fname, "r", BINARY_MODE);
  870.    if ( tfile == NULL )
  871.    {
  872.       printerr( art_fname );
  873.       panic();
  874.    }
  875.  
  876. /*--------------------------------------------------------------------*/
  877. /*    Get fields necessary for distribution (Newsgroups:)  and the    */
  878. /*    history file (Message-ID:).  Also, if the article is going      */
  879. /*    to more than one newsgroup, flag the creation of Xref: fields.  */
  880. /*--------------------------------------------------------------------*/
  881.  
  882.    n_hdrs = b_xref = 0;
  883.    while (n_hdrs < 2)
  884.    {
  885.       /* Get the next line */
  886.       gc_ptr = fgets(hist_record, sizeof(hist_record), tfile);
  887.  
  888. /*--------------------------------------------------------------------*/
  889. /*                    Check for end of the headers                    */
  890. /*--------------------------------------------------------------------*/
  891.  
  892.       if ((gc_ptr == NULL) || (strlen(hist_record) == 1))
  893.       {
  894.          /* Ooops.  Missing Message-ID: or Newsgroups: */
  895.          if (messageID == NULL)
  896.             printmsg(0, "Article has no Message-ID:, discarded");
  897.          else {
  898.             if (newsgroups == NULL)
  899.             {
  900.                printmsg(0,
  901.                     "Article %s has no Newsgroups: line, discarded",
  902.                     messageID);
  903.             } /* if */
  904.             else
  905.                break;
  906.          } /* else */
  907.  
  908.          fclose(tfile);
  909.  
  910.          return FALSE;
  911.       } /* if ((gc_ptr == NULL) || (strlen(hist_record) == 1)) */
  912.  
  913.       line_len = strlen(hist_record);
  914.  
  915.       if (hist_record[line_len-1] == '\n')
  916.          hist_record[(line_len--)-1] = '\0';
  917.  
  918.       if (hist_record[line_len-1] == '\r')
  919.          hist_record[(line_len--)-1] = '\0';
  920.  
  921.       if (equalni(hist_record, "Newsgroups:", strlen("Newsgroups:")))
  922.       {
  923.          /* Handle Newsgroups: line*/
  924.          if (newsgroups == NULL)
  925.          {
  926.             gc_ptr += strlen("Newsgroups:") + 1;
  927.             newsgroups = strcpy(groups, gc_ptr);
  928.             newsgroups[strlen(newsgroups)+1] = '\0';  /* Guard char for rescan */
  929.             n_hdrs++;
  930.             b_xref = (strchr(newsgroups, ',') != NULL); /* more than 1 group */
  931.      }                     /* i.e. do we need to create a Xrefs: line ? */
  932.          else
  933.             printmsg(0, "Article has multiple Newsgroups: lines");
  934.       }
  935.       else if (equalni(hist_record, "Message-ID:", strlen("Message-ID:")))
  936.       {
  937.          /* Handle Message-ID: line */
  938.          if (messageID == NULL)
  939.          {
  940.             gc_ptr += strlen("Message-ID:") + 1;
  941.             messageID = message_buf;
  942.             messageID[0] = '\0';
  943.             if (*gc_ptr != '<') strcat(messageID, "<");
  944.                strcat(messageID, gc_ptr);
  945.             if (messageID[strlen(messageID)-1] != '>')
  946.                strcat(messageID,">");
  947.             n_hdrs++;
  948.          } /* if (messageID == NULL) */
  949.       }
  950.    }  /* while getting Newsgroups: and Message-ID: */
  951.  
  952. /*--------------------------------------------------------------------*/
  953. /*           Check whether article has been received before           */
  954. /*--------------------------------------------------------------------*/
  955.  
  956.    if ( bflag[ F_HISTORY ] )
  957.    {
  958.       if (is_in_history(hfile, messageID))
  959.       {
  960.          printmsg(2, "rnews: Duplicate article %s", messageID);
  961.          fclose(tfile);
  962.          return FALSE;
  963.       }
  964.  
  965.       /* Start building the history record for this article */
  966.       strcpy(hist_record, messageID);
  967.       strcat(hist_record, " ");
  968.       strcat(hist_record, history_date);
  969.       strcat(hist_record, " ");
  970.  
  971.       gc_ptr1 = newsgroups;
  972.       while ((gc_ptr = strchr(gc_ptr1, ',')) != NULL) {
  973.          gc_ptr[0] = '\0';
  974.          if (strlen(gc_ptr1) > MAXGRP - 1) { /* Bounds check the newsgroup len */
  975.             printmsg(0, "rnews: newsgroup name too long -- %s", gc_ptr1);
  976.             gc_ptr1 = gc_ptr + 1;
  977.             continue; /* Punt the newsgroup history record */
  978.          }
  979.          strcpy(groupy, gc_ptr1);
  980.          strcat(hist_record, groupy);
  981.          strcat(hist_record, ":");
  982.          gc_ptr1 = gc_ptr + 1;
  983.          get_snum(groupy,snum);
  984.          strcat(hist_record, snum);
  985.            strcat(hist_record, ",");
  986.       }
  987.       strcpy(groupy, gc_ptr1);
  988.       strcat(hist_record, groupy);
  989.       strcat(hist_record, ":");
  990.       get_snum(groupy,snum);
  991.       strcat(hist_record, snum);
  992.       strcat(hist_record, "\n");
  993.  
  994.       /* Restore the newsgroups line */
  995.       while (newsgroups[strlen(newsgroups)+1] != '\0') {
  996.          newsgroups[strlen(newsgroups)] = ',';
  997.       }
  998.  
  999.       /* Post the history record */
  1000.       fseek(hfile, 0L, SEEK_END);
  1001.       fwrite(hist_record, sizeof(char), strlen(hist_record), hfile);
  1002.    } /* if ( bflag[ F_HISTORY ] ) */
  1003.  
  1004. /*--------------------------------------------------------------------*/
  1005. /*              Now build the Xref: line (if we need to)              */
  1006. /*--------------------------------------------------------------------*/
  1007.  
  1008.    if (b_xref) {
  1009.       strcpy(hist_record, "Xref: ");
  1010.       strcat(hist_record, E_nodename);
  1011.       strcat(hist_record, " ");
  1012.  
  1013.       gc_ptr1 = newsgroups;
  1014.       while ((gc_ptr = strchr(gc_ptr1, ',')) != NULL)
  1015.       {
  1016.          gc_ptr[0] = '\0';
  1017.          if (strlen(gc_ptr1) > MAXGRP - 1) { /* Bounds check the newsgroup len */
  1018.             printmsg(0, "rnews: newsgroup name too long -- %s", gc_ptr1);
  1019.             gc_ptr1 = gc_ptr + 1;
  1020.             continue; /* Punt the newsgroup history record */
  1021.          }
  1022.          strcpy(groupy, gc_ptr1);
  1023.          strcat(hist_record, groupy);
  1024.          strcat(hist_record, ":");
  1025.          gc_ptr1 = gc_ptr + 1;
  1026.          get_snum(groupy,snum);
  1027.          strcat(hist_record, snum);
  1028.          strcat(hist_record, " ");
  1029.       }
  1030.  
  1031.       strcpy(groupy, gc_ptr1);
  1032.       strcat(hist_record, groupy);
  1033.       strcat(hist_record, ":");
  1034.       get_snum(groupy,snum);
  1035.       strcat(hist_record, snum);
  1036.       strcat(hist_record, "\n");
  1037.  
  1038.         /* Restore the newsgroups line */
  1039.       while (newsgroups[strlen(newsgroups)+1] != '\0') {
  1040.          newsgroups[strlen(newsgroups)] = ',';
  1041.       }
  1042.  
  1043.     }
  1044.  
  1045. /*--------------------------------------------------------------------*/
  1046. /*       We now need to copy the file to each group in groupys        */
  1047. /*--------------------------------------------------------------------*/
  1048.  
  1049.    gc_ptr1 = newsgroups;
  1050.    while ((gc_ptr = strchr(gc_ptr1, ',')) != NULL)
  1051.    {
  1052.       gc_ptr[0] = '\0';
  1053.       strcpy(groupy, gc_ptr1);
  1054.       gc_ptr1 = gc_ptr + 1;
  1055.       copy_file(tfile, groupy, b_xref ? hist_record : NULL);
  1056.    }
  1057.  
  1058.    strcpy(groupy, gc_ptr1);
  1059.    copy_file(tfile, groupy, b_xref ? hist_record : NULL);
  1060.    fclose(tfile);
  1061.  
  1062.    return TRUE;
  1063. } /* deliver_article */
  1064.  
  1065. /*--------------------------------------------------------------------*/
  1066. /*    f i n d _ n e w s g r o u p                                     */
  1067. /*                                                                    */
  1068. /*    Locate a news group in our list                                 */
  1069. /*--------------------------------------------------------------------*/
  1070.  
  1071. static struct grp *find_newsgroup(const char *grp)
  1072. {
  1073.    struct grp *cur = group_list;
  1074.  
  1075.    while ((strcmp(grp,cur->grp_name) != 0)) {
  1076.       if (cur->grp_next != NULL) {
  1077.          cur = cur->grp_next;
  1078.       } else {
  1079.          return NULL;
  1080.       }
  1081.    }
  1082.  
  1083.    return cur;
  1084. }
  1085.  
  1086. /*--------------------------------------------------------------------*/
  1087. /*    c o p y _ f i l e                                               */
  1088. /*                                                                    */
  1089. /*    Write an article to it's final resting place                    */
  1090. /*--------------------------------------------------------------------*/
  1091.  
  1092. static void copy_file(FILE *input,
  1093.                       char *group,
  1094.                       char *xref)
  1095. {
  1096.    struct grp *cur;
  1097.    char filename[FILENAME_MAX];
  1098.    char buf[BUFSIZ];
  1099.    FILE *output;
  1100.  
  1101. /*--------------------------------------------------------------------*/
  1102. /*           Determine if the news has been already posted            */
  1103. /*--------------------------------------------------------------------*/
  1104.  
  1105.    cur = find_newsgroup(group);
  1106.    if (cur == NULL)
  1107.    {
  1108.       printmsg(3, "rnews: Article cross-posted to %s", group);
  1109.       return;
  1110.    }
  1111.  
  1112. /*--------------------------------------------------------------------*/
  1113. /*                       Now build a file name                        */
  1114. /*--------------------------------------------------------------------*/
  1115.  
  1116.    ImportNewsGroup( filename, cur->grp_name, cur->grp_high++);
  1117.  
  1118. /*--------------------------------------------------------------------*/
  1119. /*                 We have a file name, open the file                 */
  1120. /*--------------------------------------------------------------------*/
  1121.  
  1122.    printmsg(2, "rnews: Saving %s article in %s",
  1123.                cur->grp_name, filename);
  1124.  
  1125.    if ((output = FOPEN(filename, "w",TEXT_MODE)) == nil(FILE))
  1126.    {
  1127.       printerr( filename );
  1128.       printmsg(0, "rnews: Unable to save article");
  1129.       return;
  1130.    }
  1131.  
  1132.    rewind(input);
  1133.  
  1134.    if (xref) /* write new Xref: line first */
  1135.    {
  1136.       if (fputs(xref, output) == EOF)
  1137.       {
  1138.          printerr( filename );
  1139.          panic();
  1140.       }
  1141.    }
  1142.  
  1143.    while (fgets(buf, sizeof buf, input) != NULL)
  1144.    {
  1145.  
  1146.       if (equalni(buf, "Path:", strlen("Path:")))
  1147.       {
  1148.          fprintf(output, "Path: %s!%s", E_nodename,
  1149.                          buf + strlen("Path:") + 1);
  1150.          continue;
  1151.       }
  1152.       else if (equalni(buf, "Xref:", strlen("Xref:")))
  1153.          continue; /* skip possibly old Xref: line */
  1154.  
  1155.       if (fputs(buf, output) == EOF)
  1156.       {
  1157.          printerr( filename );
  1158.          panic();
  1159.       }
  1160.    } /* while */
  1161.  
  1162.    fclose(output);
  1163.  
  1164. } /* copy_file */
  1165.  
  1166. /*--------------------------------------------------------------------*/
  1167. /*    g e t _ s n u m                                                 */
  1168. /*                                                                    */
  1169. /*    Get highest article number of newsgroup                         */
  1170. /*--------------------------------------------------------------------*/
  1171.  
  1172. static void get_snum(const char *group, char *snum)
  1173. {
  1174.    struct grp *cur;
  1175.  
  1176.    strcpy(snum, "0");
  1177.    cur = find_newsgroup(group);
  1178.    if (cur == NULL)
  1179.    return;
  1180.  
  1181.    sprintf(snum, "%d", cur->grp_high);
  1182.  
  1183. } /* snum */
  1184.  
  1185. /*--------------------------------------------------------------------*/
  1186. /*    x m i t _ n e w s                                               */
  1187. /*                                                                    */
  1188. /*    A cruel hack to transmit news to other systems                  */
  1189. /*--------------------------------------------------------------------*/
  1190.  
  1191. static void xmit_news( char *sysname, FILE *in_stream )
  1192. {
  1193.    static char *spool_fmt = SPOOLFMT;              /* spool file name */
  1194.    static char *dataf_fmt = DATAFFMT;
  1195.    static char *send_cmd  = "S %s %s %s - %s 0666\n";
  1196.    static long seqno = 0;
  1197.    FILE *out_stream;          /* For writing out data                */
  1198.  
  1199.    char buf[BUFSIZ];
  1200.    unsigned len;
  1201.  
  1202.    char msfile[FILENAME_MAX]; /* MS-DOS format name of files         */
  1203.    char msname[22];           /* MS-DOS format w/o path name         */
  1204.  
  1205.    char tmfile[15];           /* Call file, UNIX format name         */
  1206.    char ixfile[15];           /* eXecute file for remote system,
  1207.                                 UNIX format name for local system   */
  1208.    char idfile[15];           /* Data file, UNIX format name         */
  1209.    char rdfile[15];           /* Data file name on remote system,
  1210.                                  UNIX format                         */
  1211.    char rxfile[15];           /* Remote system UNIX name of eXecute
  1212.                                  file                                */
  1213.    char *seq;
  1214.  
  1215. /*--------------------------------------------------------------------*/
  1216. /*          Create the UNIX format of the file names we need          */
  1217. /*--------------------------------------------------------------------*/
  1218.  
  1219.    seqno = getseq();
  1220.    seq = JobNumber( seqno );
  1221.  
  1222.    sprintf(tmfile, spool_fmt, 'C', sysname,  'd' , seq);
  1223.    sprintf(idfile, dataf_fmt, 'D', E_nodename , seq, 'd');
  1224.    sprintf(rdfile, dataf_fmt, 'D', E_nodename , seq, 'r');
  1225.    sprintf(ixfile, dataf_fmt, 'D', E_nodename , seq, 'e');
  1226.    sprintf(rxfile, dataf_fmt, 'X', E_nodename , seq, 'r');
  1227.  
  1228. /*--------------------------------------------------------------------*/
  1229. /*                     create remote X (xqt) file                     */
  1230. /*--------------------------------------------------------------------*/
  1231.  
  1232.    importpath( msname, ixfile, sysname);
  1233.    mkfilename( msfile, E_spooldir, msname);
  1234.  
  1235.    out_stream = FOPEN(msfile, "w", BINARY_MODE);
  1236.    if ( out_stream == NULL )
  1237.    {
  1238.       printmsg(0, "xmit_news: cannot open X file %s", msfile);
  1239.       printerr(msfile);
  1240.       return ;
  1241.    } /* if */
  1242.  
  1243.    if (setvbuf( out_stream, NULL, _IONBF, 0))
  1244.    {
  1245.       printmsg(0, "xmit_news: Cannot unbuffer file %s (%s).",
  1246.                   ixfile, msfile);
  1247.       printerr(msfile);
  1248.       panic();
  1249.    } /* if */
  1250.  
  1251.    fprintf(out_stream, "R %s %s\nU %s %s\nF %s\nI %s\nC rnews\n",
  1252.                "uucp", E_domain,
  1253.                "uucp", E_nodename,
  1254.                rdfile, rdfile);
  1255.    fclose(out_stream);
  1256.  
  1257. /*--------------------------------------------------------------------*/
  1258. /*  Create the data file with the mail to send to the remote system   */
  1259. /*--------------------------------------------------------------------*/
  1260.  
  1261.    importpath(msname, idfile, sysname);
  1262.    mkfilename( msfile, E_spooldir, msname);
  1263.  
  1264.    out_stream = FOPEN(msfile, "w", BINARY_MODE);
  1265.    if (out_stream == NULL )
  1266.    {
  1267.       printerr(msfile);
  1268.       printmsg(0,
  1269.                "xmit_news: Cannot open spool file \"%s\" for output",
  1270.                 msfile);
  1271.       return;
  1272.    }
  1273.  
  1274.    if (setvbuf( out_stream, NULL, _IONBF, 0))
  1275.    {
  1276.       printmsg(0, "xmit_news: Cannot unbuffer file %s (%s).",
  1277.                   idfile, msfile);
  1278.       printerr(msfile);
  1279.       panic();
  1280.    } /* if */
  1281.  
  1282. /*--------------------------------------------------------------------*/
  1283. /*                       Loop to copy the data                        */
  1284. /*--------------------------------------------------------------------*/
  1285.  
  1286.    while ( (len = fread( buf, 1, sizeof buf, in_stream)) != 0)
  1287.    {
  1288.       if (fwrite( buf, 1, len, out_stream ) != len)     /* I/O error?               */
  1289.       {
  1290.          printerr(msfile);
  1291.          fclose(out_stream);
  1292.          return;
  1293.       } /* if */
  1294.    } /* while */
  1295.  
  1296.    fclose( out_stream );
  1297.  
  1298. /*--------------------------------------------------------------------*/
  1299. /*                     create local C (call) file                     */
  1300. /*--------------------------------------------------------------------*/
  1301.  
  1302.    importpath( msname, tmfile, sysname);
  1303.    mkfilename( msfile, E_spooldir, msname);
  1304.  
  1305.    out_stream = FOPEN(msfile, "w",TEXT_MODE);
  1306.    if (out_stream == NULL)
  1307.    {
  1308.       printerr( msname );
  1309.       printmsg(0, "xmit_news: cannot open C file %s", msfile);
  1310.       return;
  1311.    }
  1312.  
  1313.    fprintf(out_stream, send_cmd, idfile, rdfile,
  1314.                   "uucp", idfile);
  1315.    fprintf(out_stream, send_cmd, ixfile, rxfile,
  1316.                   "uucp", ixfile);
  1317.    fclose(out_stream);
  1318.  
  1319. } /* xmit_news */
  1320.  
  1321. /*--------------------------------------------------------------------*/
  1322. /*    c o p y _ s n e w s                                             */
  1323. /*                                                                    */
  1324. /*    Process news destined for the simple news reader                */
  1325. /*--------------------------------------------------------------------*/
  1326.  
  1327. static int copy_snews( char *filename, FILE *stream )
  1328. {
  1329.    char buf[BUFSIZ];
  1330.    size_t len;
  1331.  
  1332.    FILE *out_stream = FOPEN(filename, "w", BINARY_MODE);
  1333.  
  1334.    if ( out_stream == NULL )
  1335.    {
  1336.       printerr(filename);
  1337.       panic();
  1338.    } /* if */
  1339.  
  1340.    if (setvbuf( out_stream, NULL, _IONBF, 0))
  1341.    {
  1342.       printmsg(0, "copy_snews: Cannot unbuffer file %s.", filename);
  1343.       printerr(filename);
  1344.       panic();
  1345.    } /* if */
  1346.  
  1347. /*--------------------------------------------------------------------*/
  1348. /*                          Perform the copy                          */
  1349. /*--------------------------------------------------------------------*/
  1350.  
  1351.    while ( (len = fread( buf, 1, sizeof buf, stream)) != 0)
  1352.    {
  1353.       if (fwrite( buf, 1, len, out_stream ) != len)     /* I/O error? */
  1354.       {
  1355.          printerr(filename);
  1356.          panic();
  1357.       } /* if */
  1358.    } /* while */
  1359.  
  1360. /*--------------------------------------------------------------------*/
  1361. /*                           Close the file                           */
  1362. /*--------------------------------------------------------------------*/
  1363.  
  1364.    fclose( out_stream );
  1365.    fclose( stream );
  1366.    return 0;
  1367.  
  1368. } /* copy_snews */
  1369.